package pro2

import (
	"fmt"
	"goodlink/md5"
	"goodlink/pro"
	"goodlink/proxy"
	"goodlink/utils"
	"goodlink2/tun2"
	"log"
	"net"
	"strings"
	"time"

	"github.com/quic-go/quic-go"
)

var (
	m_local_state = 0 //0: 停止, 1: 启动, 2: 连接成功
)

func GetLocalTCPConn(l *net.Listener, tcp_addr *net.TCPAddr, addr *pro.AddrType, conn_type int, count int) (*tun2.TunActive, *tun2.TunPassive, quic.Connection, quic.Stream, error) {
	var tun_active *tun2.TunActive
	var tun_passive *tun2.TunPassive

	SessionID := string(utils.RandomBytes(24))
	utils.Log().DebugF("会话ID: %s", SessionID)

	redisJson := pro.RedisJsonType{
		State:        0,
		SessionID:    SessionID,
		ConnectCount: count,
	}

	switch conn_type {
	case 0:
		utils.Log().Debug("请求连接对端")

	default:
		redisJson.LocalAddr = *addr
		utils.Log().DebugF("发送本端地址: %v", redisJson.LocalAddr)
	}

	pro.RedisSet(15*time.Second, &redisJson)

	for m_local_state == 1 {
		time.Sleep(1 * time.Second)

		if pro.RedisGet(&redisJson) != nil {
			log.Println("会话超时")
			return tun_active, tun_passive, nil, nil, nil
		}

		//log.Printf("状态消息: %v", redisJson)

		utils.Log().SetDebugSate(redisJson.State)

		if !strings.EqualFold(redisJson.SessionID, SessionID) {
			utils.Log().Debug("会话被重置")
			return tun_active, tun_passive, nil, nil, nil
		}

		switch redisJson.State {
		case 1:
			utils.Log().DebugF("收到对端地址: %v", redisJson.RemoteAddr)

			switch conn_type {
			case 0:
				if tun_passive != nil {
					tun_passive.Release()
				}
				tun_active = nil

				redisJson.LocalAddr = *addr

				tun_passive = tun2.CteateTunPassive([]byte(redisJson.SessionID), l, tcp_addr, redisJson.RemoteAddr.WanIPv4, redisJson.RemoteAddr.WanPort1, redisJson.RemoteAddr.WanPort2, redisJson.SendPortCount)
				tun_passive.Start()

				redisJson.State = 2
				utils.Log().DebugF("发送本端地址: %v", redisJson.LocalAddr)
				pro.RedisSet(redisJson.RedisTimeOut, &redisJson)

			default:
				if tun_active != nil {
					tun_active.Release()
				}
				tun_passive = nil

				tun_active = tun2.CreateTunActive([]byte(redisJson.SessionID), l, tcp_addr)

				if redisJson.LocalAddr.IPv6 != "" && redisJson.RemoteAddr.IPv6 != "" {
					utils.Log().Debug("IPv6直连")
					tun_active.Start1(redisJson.RemoteAddr.IPv6, redisJson.RemoteAddr.LocalPort, 0)

				} else if redisJson.LocalAddr.WanIPv4 == redisJson.RemoteAddr.WanIPv4 {
					utils.Log().Debug("内网直连")
					tun_active.Start1(redisJson.RemoteAddr.LocalIPv4, redisJson.RemoteAddr.LocalPort, 0)

				} else {
					tun_active.Start(redisJson.LocalAddr.WanPort1, redisJson.LocalAddr.WanPort2, redisJson.RemoteAddr.WanIPv4, redisJson.RemoteAddr.WanPort1, redisJson.RemoteAddr.WanPort2)
				}

				redisJson.State = 2
				pro.RedisSet(redisJson.RedisTimeOut, &redisJson)
			}

		case 3:
			if tun_passive != nil {
				if tun_passive.TunQuicConn != nil {
					utils.Log().DebugF("连接成功")
					return tun_active, tun_passive, tun_passive.TunQuicConn, tun_passive.TunHealthStream, nil
				}
			}
			if tun_active != nil {
				if tun_active.TunQuicConn != nil {
					utils.Log().DebugF("连接成功")
					return tun_active, tun_passive, tun_active.TunQuicConn, tun_active.TunHealthStream, nil
				}
			}
			utils.Log().Debug("连接失败")
			return tun_active, tun_passive, nil, nil, nil

		case 4:
			utils.Log().Debug("连接超时")
			return tun_active, tun_passive, nil, nil, nil

		default:
			utils.Log().DebugF("等待对端状态: Local: %v => Remote: %v", redisJson.LocalAddr, redisJson.RemoteAddr)
		}
	}

	return tun_active, tun_passive, nil, nil, nil
}

func GetLocalStats() int {
	return m_local_state
}

var (
	m_tun_active  *tun2.TunActive
	m_tun_passive *tun2.TunPassive
)

func StopLocal() error {
	m_local_state = 0
	Release(m_tun_active, m_tun_passive)
	return nil
}

func RunLocal(conn_type int, tun_local_addr string, tun_key string) error {
	m_local_state = 1

	utils.Log().DebugF("绑定端口: %v", tun_local_addr)

	chain := make(chan int, 1)

	listener, err := net.Listen("tcp", tun_local_addr)
	if listener == nil || err != nil {
		return fmt.Errorf("绑定端口失败: %v", tun_local_addr)
	}
	defer func() {
		listener.Close()
		close(chain)
	}()

	m_tun_key = tun_key
	m_md5_tun_key = md5.Encode(tun_key)

	count := 0

	l, dialer, addr := GetTCPAddr()
	defer (*l).Close() // 注意这里我们延迟关闭监听者，但不关闭端口

	for m_local_state == 1 {

		log.Printf("本端地址: %v", addr)

		count++

		tun_active, tun_passive, conn, _, err := GetLocalTCPConn(l, dialer, &addr, conn_type, count)
		if err != nil {
			Release(tun_active, tun_passive)
			return err
		}
		if conn == nil {
			Release(tun_active, tun_passive)
			continue
		}

		m_tun_active = tun_active
		m_tun_passive = tun_passive

		go func() {
			proxy.ProcessProxyClient(listener, conn)
			chain <- 1
		}()

		m_local_state = 2
		//tun2.ProcessHealth(health)
		if m_local_state != 0 {
			m_local_state = 1
		}
		utils.Log().DebugF("释放连接: %v", conn.LocalAddr())
		Release(tun_active, tun_passive)

		if conn, err := net.Dial("tcp", tun_local_addr); conn != nil && err == nil {
			conn.Write([]byte("hello"))
			conn.Close() // 关闭连接
		}

		<-chain
		count = 0
	}

	return nil
}
